// ReMapKeyDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ReMapKey.h"
#include "ReMapKeyDlg.h"
#include <string>
#include<time.h>
#include <iostream>
#include <fstream>

using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//typedef CONST CHAR *LPCSTR, *PCSTR;
//typedef CONST WCHAR *LPCWSTR, *PCWSTR;
//
//#ifdef  UNICODE
//  typedef LPCWSTR LPCTSTR;
//#else
//  typedef LPCSTR LPCTSTR;
//#endif

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL WINAPI ConsoleEventHandler(DWORD dwCtrlType); // for graceful exit
DWORD dwMainThread = 0; // because apparently the console event handler thread for Ctrl+C is different from the main thread

HANDLE AutoThread;
DWORD AutoThreadID;
DWORD WINAPI AutoThreadProc(LPVOID);
int processButton(DWORD vkCode, DWORD leftGetCurSel, DWORD rightGetCurSel, int getCheck, WPARAM wParam);

// CReMapKeyDlg dialog
int autodelay = 100;
int x;
volatile int down;
int oldv;
int codev;
int codeh;
HHOOK hHook;
HINSTANCE appInstance;
int vcode[] = {0x00, 0x00, 0x01, 0x03, 0x04, 0x08, 0x09, 0x0C, 0x0D, 0x10, 0x11, 0x12, 0x13, 
         0x14, 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 
         0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 
         0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 
         0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x60, 0x61, 
         0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 
         0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 
         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x90, 0x91, 0xA0, 0xA1, 0xA2, 0xA3, 
         0xA4, 0xA5, 0xFA, 0xFB, 0x5B, 0x5C, 0x5D, 0x5F};
bool autoON[9];
long double sysTime;
clock_t last = 0;
clock_t current = 0;

CComboBox *Combo1Left = new CComboBox;
CComboBox *Combo1Right = new CComboBox;
CComboBox *Combo2Left = new CComboBox;
CComboBox *Combo2Right = new CComboBox;
CComboBox *Combo3Left = new CComboBox;
CComboBox *Combo3Right = new CComboBox;
CButton *checkbox[8];
CString text1;
ofstream myfile;
boolean mouseDown = false;

string comboLeft[] =  {"", "Invalid key1     ", "Invalid key2      ", "Invalid key3            ", "Invalid key4                            ", "BACKSPACE key", "TAB key", "CLEAR key", "ENTER key", "Invalid key5", "Invalid key6", "Invalid key7", "PAUSE key", "CAPS LOCK key", "ESC key", "SPACEBAR", "PAGE UP key", "PAGE DOWN key", "END key", "HOME key", "LEFT ARROW key", "UP ARROW key", "RIGHT ARROW key", "DOWN ARROW key", "SELECT key", "PRINT key", "EXECUTE key", "PRINT SCREEN key", "INS key", "DEL key", "HELP key", "0 key", "1 key", "2 key", "3 key", "4 key", "5 key", "6 key", "7 key", "8 key", "9 key", "A key", "B key", "C key", "D key", "E key", "F key", "G key", "H key", "I key", "J key", "K key", "L key", "M key", "N key", "O key", "P key", "Q key", "R key", "S key", "T key", "U key", "V key", "W key", "X key", "Y key", "Z key", "Numeric keypad 0 key", "Numeric keypad 1 key", "Numeric keypad 2 key", "Numeric keypad 3 key", "Numeric keypad 4 key", "Numeric keypad 5 key", "Numeric keypad 6 key", "Numeric keypad 7 key", "Numeric keypad 8 key", "Numeric keypad 9 key", "Separator key", "Subtract key", "Decimal key", "Divide key", "F1 key", "F2 key", "F3 key", "F4 key", "F5 key", "F6 key", "F7 key", "F8 key", "F9 key", "F10 key", "F11 key", "F12 key", "F13 key", "F14 key", "F15 key", "F16 key", "F17 key", "F18 key", "F19 key", "F20 key", "F21 key", "F22 key", "F23 key", "F24 key", "NUM LOCK key", "SCROLL LOCK key", "Left SHIFT key", "Right SHIFT key", "Left CONTROL key", "Right CONTROL key", "Left MENU key", "Right MENU key", "Play key", "Zoom key", "Left Win Key", "Right Win Key", "Applications Key", "Sleep Key"};
string comboRight[] = {"", "Left mouse button", "Right mouse button", "Control-break processing", "Middle mouse button (three-button mouse)", "BACKSPACE key", "TAB key", "CLEAR key", "ENTER key", "SHIFT key   ", "CTRL key    ", "ALT key     ", "PAUSE key", "CAPS LOCK key", "ESC key", "SPACEBAR", "PAGE UP key", "PAGE DOWN key", "END key", "HOME key", "LEFT ARROW key", "UP ARROW key", "RIGHT ARROW key", "DOWN ARROW key", "SELECT key", "PRINT key", "EXECUTE key", "PRINT SCREEN key", "INS key", "DEL key", "HELP key", "0 key", "1 key", "2 key", "3 key", "4 key", "5 key", "6 key", "7 key", "8 key", "9 key", "A key", "B key", "C key", "D key", "E key", "F key", "G key", "H key", "I key", "J key", "K key", "L key", "M key", "N key", "O key", "P key", "Q key", "R key", "S key", "T key", "U key", "V key", "W key", "X key", "Y key", "Z key", "Numeric keypad 0 key", "Numeric keypad 1 key", "Numeric keypad 2 key", "Numeric keypad 3 key", "Numeric keypad 4 key", "Numeric keypad 5 key", "Numeric keypad 6 key", "Numeric keypad 7 key", "Numeric keypad 8 key", "Numeric keypad 9 key", "Separator key", "Subtract key", "Decimal key", "Divide key", "F1 key", "F2 key", "F3 key", "F4 key", "F5 key", "F6 key", "F7 key", "F8 key", "F9 key", "F10 key", "F11 key", "F12 key", "F13 key", "F14 key", "F15 key", "F16 key", "F17 key", "F18 key", "F19 key", "F20 key", "F21 key", "F22 key", "F23 key", "F24 key", "NUM LOCK key", "SCROLL LOCK key", "Left SHIFT key", "Right SHIFT key", "Left CONTROL key", "Right CONTROL key", "Left MENU key", "Right MENU key", "Play key", "Zoom key", "Left Win Key", "Right Win Key", "Applications Key", "Sleep Key"};



CReMapKeyDlg::CReMapKeyDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CReMapKeyDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CReMapKeyDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CReMapKeyDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDOK, &CReMapKeyDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDCANCEL, &CReMapKeyDlg::OnBnClickedCancel)
	ON_BN_CLICKED(IDC_BUTTON1, &CReMapKeyDlg::OnBnClickedButton1)
END_MESSAGE_MAP()


// CReMapKeyDlg message handlers

BOOL CReMapKeyDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	text1 = L"INIT";
	SetDlgItemText(IDC_STATIC, text1);
	text1 = L"500";
	SetDlgItemText(IDC_EDIT1, text1);

	for(x = 0; x < 9; x++)
	{
		autoON[x] = false;
	}
	down = 0;

	//Create Drop Down Box
    Combo1Left->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,
		   CRect(10, 50, 160, 250), this, 0x1448);
    Combo1Right->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,
		   CRect(170, 50, 320, 250), this, 0x1448);
    Combo2Left->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,
		   CRect(10, 80, 160, 280), this, 0x1448);
    Combo2Right->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,
		   CRect(170, 80, 320, 280), this, 0x1448);
    Combo3Left->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,
		   CRect(10, 110, 160, 310), this, 0x1448);
    Combo3Right->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL,
		   CRect(170, 110, 320, 310), this, 0x1448);

	for(int x = 0; x < sizeof(comboLeft) / sizeof(string); x++)
	{
		Combo1Left->AddString(comboLeft[x].c_str());
		Combo1Right->AddString(comboRight[x].c_str());
		Combo2Left->AddString(comboLeft[x].c_str());
		Combo2Right->AddString(comboRight[x].c_str());
		Combo3Left->AddString(comboLeft[x].c_str());
		Combo3Right->AddString(comboRight[x].c_str());
	}

	Combo1Left->SetCurSel(15);
	Combo1Right->SetCurSel(10);

	//Create Check Box
    checkbox[0] = new CButton;
    checkbox[0]->Create(_T("&Break"),
    		      WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		      CRect(10, 5, 140, 35), this, 0x11);
	checkbox[1] = new CButton;
    checkbox[1]->Create(_T(""),
    		      WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		      CRect(330, 50, 350, 70), this, 0x11);
	checkbox[2] = new CButton;
    checkbox[2]->Create(_T(""),
    		      WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		      CRect(330, 80, 350, 100), this, 0x11);
	checkbox[3] = new CButton;
    checkbox[3]->Create(_T(""),
    		      WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		      CRect(330, 110, 350, 130), this, 0x11);

	
	AutoThread = CreateThread(0,0,AutoThreadProc,0,0,&AutoThreadID);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CReMapKeyDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CReMapKeyDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	KBDLLHOOKSTRUCT *pKeyBoard = (KBDLLHOOKSTRUCT *)lParam;
	if(pKeyBoard->vkCode == vcode[Combo1Left->GetCurSel()])
	{
		processButton(pKeyBoard->vkCode, Combo1Left->GetCurSel(), Combo1Right->GetCurSel(), checkbox[0]->GetCheck(), wParam);
		return 1;
	}
	else if(pKeyBoard->vkCode == vcode[Combo2Left->GetCurSel()])
	{
		processButton(pKeyBoard->vkCode, Combo2Left->GetCurSel(), Combo2Right->GetCurSel(), checkbox[1]->GetCheck(), wParam);
		return 1;
	}
	else if(pKeyBoard->vkCode == vcode[Combo3Left->GetCurSel()])
	{
		processButton(pKeyBoard->vkCode, Combo3Left->GetCurSel(), Combo3Right->GetCurSel(), checkbox[2]->GetCheck(), wParam);
		return 1;
	}
	else
	{
		return CallNextHookEx( NULL, nCode, wParam, lParam );
	}
	return 0;
}


BOOL WINAPI ConsoleEventHandler(DWORD dwCtrlType)
{
	switch(dwCtrlType)
	{
		case CTRL_C_EVENT:
		case CTRL_CLOSE_EVENT:
			PostThreadMessage(dwMainThread, WM_QUIT, NULL, NULL);
			return TRUE;

		default:
			return FALSE;
	}
}

void CReMapKeyDlg::OnBnClickedOk()
{
	// TODO: Add your control notification handler code here
	int left,right;
	CString Left1Text,Right1Text;
	//GetDlgItemText(Combo1Left, Left1Text);
	left = Combo1Left->GetCurSel();
	right = Combo1Right->GetCurSel();
	oldv = vcode[left];
	codev = vcode[right];
	codeh = MapVirtualKey(vcode[right],0);
	Left1Text.Format(_T("%d"),left);
	//MessageBox(Left1Text);

	text1.Format(_T("START[0x%x]->[0x%x]"),vcode[left],vcode[right]);
	SetDlgItemText(IDC_STATIC, text1);

	GetDlgItemText(IDC_EDIT1, text1);
	if(_ttoi(text1) > 0 && _ttoi(text1) < 9999)
	{
		autodelay = _ttoi(text1);
	}
	else
	{
		text1.Format(_T("%d"),autodelay);
		SetDlgItemText(IDC_EDIT1, text1);
	}

	//DWORD count = 0;
	//HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	//WriteConsoleA(hStdOut, message, sizeof(message)-2, &count, NULL);

	if (!SetConsoleCtrlHandler(ConsoleEventHandler, TRUE))
	{
		return;
	}
	else
	{
		dwMainThread = GetCurrentThreadId();
	}

	// Retrieve the applications instance
	appInstance = GetModuleHandle(NULL);
 
	// Attach global keyboard hook to capture keystrokes
	if (hHook)
		UnhookWindowsHookEx(hHook);
	hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, appInstance, 0);
	if (!hHook)
		return;

	//OnOK();
}

void CReMapKeyDlg::OnBnClickedCancel()
{
	// TODO: Add your control notification handler code here
	// Clean up
	//OnCancel();
	exit(1);
}


void CReMapKeyDlg::OnBnClickedButton1()
{
	// TODO: Add your control notification handler code here
	text1 = L"END";
	SetDlgItemText(IDC_STATIC, text1);

	for(x = 0; x < 9; x++)
	{
		autoON[x] = false;
	}

	if (hHook)
	{
		UnhookWindowsHookEx(hHook);
		SetConsoleCtrlHandler(ConsoleEventHandler, FALSE);
	}
}

DWORD WINAPI AutoThreadProc(LPVOID argv)
{	
	HANDLE startscan = CreateEvent(NULL,TRUE,FALSE, TEXT("AUTO"));
	while(1)
	{
		WaitForSingleObject(startscan,autodelay);
		if (checkbox[1]->GetCheck() == 1 && autoON[1] == true)
		{
			keybd_event(vcode[Combo1Right->GetCurSel()], MapVirtualKey(vcode[Combo1Right->GetCurSel()],0), KEYEVENTF_EXTENDEDKEY, 0);
			keybd_event(vcode[Combo1Right->GetCurSel()], MapVirtualKey(vcode[Combo1Right->GetCurSel()],0), KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0);
		}
		if (checkbox[2]->GetCheck() == 1 && autoON[2] == true)
		{
			keybd_event(vcode[Combo2Right->GetCurSel()], MapVirtualKey(vcode[Combo2Right->GetCurSel()],0), KEYEVENTF_EXTENDEDKEY, 0);
			keybd_event(vcode[Combo2Right->GetCurSel()], MapVirtualKey(vcode[Combo2Right->GetCurSel()],0), KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0);
		}
		if (checkbox[3]->GetCheck() == 1 && autoON[3] == true)
		{
			keybd_event(vcode[Combo3Right->GetCurSel()], MapVirtualKey(vcode[Combo3Right->GetCurSel()],0), KEYEVENTF_EXTENDEDKEY, 0);
			keybd_event(vcode[Combo3Right->GetCurSel()], MapVirtualKey(vcode[Combo3Right->GetCurSel()],0), KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0);
		}
	}
	return 0;
}

int processButton(DWORD vkCode, DWORD leftGetCurSel, DWORD rightGetCurSel, int getCheck, WPARAM wParam)
{
	{
		switch (wParam)
		{
		case WM_KEYDOWN:
			current = clock();
			if((current - last) < autodelay)
			{
				return 1;
			}
			last = current;
			if(rightGetCurSel < 5)
			{
				if(mouseDown == false)
				{
					mouseDown = true;
					switch(rightGetCurSel)
					{
					case 1:
						mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
						if (getCheck == 1)
						{
							mouseDown = false;
							mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
						}
						break;
					case 2:
						mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
						if (getCheck == 1)
						{
							mouseDown = false;
							mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
						}
						break;
					case 4:
						mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
						if (getCheck == 1)
						{
							mouseDown = false;
							mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
						}
						break;
					}
				}
			}
			else
			{
				keybd_event(vcode[rightGetCurSel], MapVirtualKey(vcode[rightGetCurSel],0), KEYEVENTF_EXTENDEDKEY, 0);
				autoON[1] = !autoON[1];
				if (getCheck == 1)
				{
					keybd_event(vcode[rightGetCurSel], MapVirtualKey(vcode[rightGetCurSel],0), KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0);

				}
			}
			return 1;
		case WM_KEYUP:
			last = 0;
			if(rightGetCurSel < 5)
			{
				mouseDown = false;
				switch(rightGetCurSel)
				{
				case 1:
					mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
					break;
				case 2:
					mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
					break;
				case 4:
					mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
					break;
				}
			}
			else
			{
				keybd_event(vcode[rightGetCurSel], MapVirtualKey(vcode[rightGetCurSel],0), KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0);
			}
			return 1;
		}
	}
	return 0;
}